--
-- @Author:      name
-- @DateTime:    20189-07-30 23:05:48
-- @Description: 所有游戏桌子共用到的消息


local cjson = require("cjson")

local table_insert = table.insert
local math_floor = math.floor

local M = class("Handler")

---------------------------------------------------------
-- Private
---------------------------------------------------------
function M:ctor()
	self.fpath = g.getenv("base_root") --框架所在目录
	self.sh_golan = self.fpath .. "depends/golib/golan" --去除汉字
	self.msg_delay = {} --标记发送过消息
	self:register()
end

--注册本服务里的消息
function M:register()

	g.register("C2_TS_leave", handler(self, self.reqLeaveDesk))
	g.register("C2_TS_sit", handler(self, self.reqSitDown))
	g.register("C2_TS_standup", handler(self, self.reqStandUp))
	g.register("C2_TS_message", handler(self, self.reqMessage))
	g.register("C2_TS_showcard", handler(self, self.reqShowCard))
	g.register( "C2_TS_auto_oper", handler(self, self.reqAutoOper))

	g.register("enter_desk", handler(self, self.onEnterDesk))
	g.register("get_playing_num", handler(self, self.onGetPlayingNum))
	g.register("get_seating_num", handler(self, self.onGetSeatingNum))
	g.register("get_users_num", handler(self, self.onGetUsersNum))

	g.register("disconnect", handler(self, self.onDisconnect))
	g.register("kick_user", handler(self, self.onKickUser))

	g.register( "remove_robots", handler(self, self.onRemoveRobots))


	if self.testHotfix then
		self:testHotfix()
	end
	if g.room_cfg then
		g.fork(function() self:loadConfig() end)
	else
		self:loadConfig()
	end
end

--加载房间配置
function M:loadConfig()
	if g.rtype == g.const.room_type.match then
		--比赛场
		g.blind_cfg = g.callConfig("get", "blind_cfg")
		g.room_cfg = g.room_cfg or {}
		g.room_cfg.min_buy = 100
		g.room_cfg.max_buy = 1000000000000
		g.room_cfg.max_limit = 1000000000000
		g.room_cfg.fee_rate = 0
		g.room_cfg.min_fee = 0
		g.room_cfg.max_fee = 0
	else
		if g.room_cfg_name then
			g.room_cfg = g.callConfig("get", g.room_cfg_name, g.rid)
			--print("11111111111", g.rid, g.room_cfg_name)
			--print("222222222", tostring(g.room_cfg))
		else
			g.room_cfg = g.callConfig("get", "room_cfg", g.rid)
		end

	end
	g.log:deskDebug(0, "g.room_cfg:", g.rtype, g.room_cfg)
end


--进入普通桌子, 先不坐下
--进入的是比赛场的是自动坐下
function M:onEnterDesk(msg)
	--g.log:deskDebug(msg.mid, "1onEnterDesk:", msg)
	local uid = msg.mid
	local user = g.user_mgr:getUser(uid)
	if not user then
		user = g.user_mgr:addUser(uid, msg.user_data)
	else
		user:initUser(msg.user_data)
		msg.chips = user:getChip() --不是第一次进入
	end
	user:setDisconnect(false)
	user:setInfo(msg.info)
	if g.desk.enterDeskCallback then
		g.desk:enterDeskCallback(user, msg)
	end
	local desk_info = g.desk:getDeskInfo(uid)
	if g.rtype == g.const.room_type.match then
		desk_info.selfuser.match_rank = msg.match_rank or 0
	end
	g.log:deskDebug(msg.mid, "onEnterDesk:", desk_info)

	return desk_info
end

--离开
function M:reqLeaveDesk(msg)
	g.log:deskInfo(msg.mid, "reqLeaveDesk", msg)
	local uid = msg.uid
	local user = g.user_mgr:getUser(uid)
	if not user then --玩家不在这个桌子里
		g.log:deskInfo(msg.mid, "reqLeaveDesk, not in desk", msg)
		return {
			code = g.error_code.desk_user_err,
			tid = g.desk_id,
		}
	end
	if g.desk.leaveCallback then
		local res = g.desk:leaveCallback(user) --让各个游戏做它要做的事
		if res then
			return res
		end
	end

	return {
		code = 0,
		tid = g.desk_id,
	}
end

-- 请求坐下
function M:reqSitDown(msg, no_send)
	g.log:deskInfo(msg.mid, "reqSitDown", msg)
	local uid = msg.mid
	local sid = msg.seatid
	local chips = msg.chips
	local user = g.user_mgr:getUser(uid)
	if not user then --玩家不在这个桌子里
		--g.log:err("reqSitDown，玩家不在这个桌子里", msg)
		g.log:deskDebug(uid, "reqSitDown not in desk")
		return {code = g.error_code.desk_user_err, tid = g.desk_id}
	end
	--判断筹码的合法性
	local cfg = g.room_cfg
	--print("cfg", tostring(cfg))
	if chips < cfg.min_buy then
		g.log:deskInfo(uid, string.format("reqSitDown chips err chips:%s min_buy:%s max_limit:%s", chips, cfg.min_buy, cfg.max_limit))
		return {code = g.error_code.invalid_room_min_buy, tid = g.desk_id}
	end
	if chips > cfg.max_limit then
		return {code = g.error_code.invalid_room_max_limit, tid = g.desk_id}
	end
	local seat_id = user:getSeatId()
	if seat_id and seat_id > 0 then
		--已经坐下
		return {code = g.error_code.fail, tid = g.desk_id}
	end
	local seat_id = g.user_mgr:sitDown(uid, sid)
	if seat_id then
		if g.desk.sitDownCallback then --让各个游戏做它要做的事
			g.desk:sitDownCallback(uid)
		end
		if not msg.rtype or msg.rtype == g.const.room_type.normal then
			--普通场从游戏帐户中扣除
			local err = user:buyChip(chips)
			if err then return err end
		else
			user:setChip(chips) --设置玩家在桌子上的金币
		end
		user:setNoOperNum(0)
		user:setNoOperRound(0)
		user:setRound(0)
		user:setAutoPlay(0)
		if not no_send then
			--通知所有玩家有人坐下
			local data = {
				tid = g.desk_id,
				mid = uid,
				seatid = seat_id,
				seat_chips = user:getChip(),
				info = user:getInfo(),
				other = "",
			}
			--print("####TS_2C_sitBc###data#######", tostring(data))
			g.desk:sendUsers("TS_2C_sitBc", data)
		end

		return {
			code = g.error_code.ok,
			seatid = seat_id,
			tid = g.desk_id,
		}
	end
	return {
		code = g.error_code.seat_down_err,
		tid = g.desk_id,
	}
end

-- 请求站起
function M:reqStandUp(msg)
	--print("#######reqStandUp", tostring(msg))
	local user_id = msg.mid
	local user = g.user_mgr:getUser(user_id)
	local seat_id = user:getSeatId()
	if not user or seat_id <= 0 then --玩家不在这个桌子里
		g.log:deskDebug(msg.mid, "reqStandUp not in desk", msg)
		return {
			code = g.error_code.desk_user_err,
			tid = g.desk_id,
		}
	end
	if g.desk.standUpCallback then --让各个游戏做它要做的事
		g.desk:standUpCallback(user)
	end

	return {
		code = 0,
		tid = g.desk_id,
	}

end

--消息
function M:reqMessage(req_data)
	local uid = req_data.mid
	local user = g.user_mgr:getUser(uid)
	if not user then
		g.log:deskDebug(uid, "reqMessage not in desk", req_data)
		return {code = g.error_code.desk_user_err, tid = g.desk_id}
	end
	if self.msg_delay[uid] then
		--发送消息太快
		return {code = g.error_code.too_msg, tid = g.desk_id}
	end
	self.msg_delay[uid] = true
	g.timeout(2, function()
		self.msg_delay[uid] = nil
	end)
	if req_data.msg then
		local ok, tb = pcall(cjson.decode, req_data.msg)
		if ok and tb then
			if tb.type == "seat_info" then
				--更新玩家信息
				user:setInfo(cjson.encode(tb.info))
			end
			if tb.msg then
				local tb_cmd = string.split(tb.msg, ":")
				if tb_cmd and next(tb_cmd) then
					--测试jackpot
					g.rule:testCmd(tb_cmd)
				end

				if g.const.switch.filter_chinese then
					--过滤掉中文
					--tb.msg = string.gsub(tb.msg, "[\127-\254]", "*") --lua 这种方式会把的文字过滤如印地语，但用
					tb.msg = string.filter_chinese(tb.msg)

					--go写的这个就能只过滤汉字
					--local sh = string.format("%s %s", self.sh_golan, tb.msg)
					--local fd = io.popen(sh, "r")
					--local output = fd:read("*a")
					--fd:close()
					--tb.msg = output
					--print("output:", output)
				end
				if g.const.switch.word_filter then
					--发送过来的消息, 过滤下敏感字
					local ok, str = g.callAdmin( "word_filter", tb.msg)
					if ok and str then
						tb.msg = str
						print("word_filter:", str)
					end
				end
				req_data.msg = cjson.encode(tb)
			end
		else
			return {code = g.error_code.fail, tid = g.desk_id}
		end
	end
	--通知所有玩家
	local data = {
		tid = g.desk_id,
		mid = uid,
		msg = req_data.msg,
	}
	g.desk:sendUsers("TS_2C_messageBc", data)
	return {code = g.error_code.ok, tid = g.desk_id}
end

--亮牌
function M:reqShowCard(msg)
	if g.desk:getStage() == g.desk.s_stage_rest then
		return
	end
	local uid = msg.mid
	local user = g.user_mgr:getUser(uid)
	if not user then
		return {code = g.error_code.desk_user_err, tid = g.desk_id}
	end
	if not user:isSeating() then
		return {code = g.error_code.input_err, tid = g.desk_id}
	end
	local sid = user:getSeatId()
	local cards = msg.cards or {}
	if not next(cards) or table.size(cards) ~= 2 then
		cards = nil
	else
		local user_cards = user:getCards()
		local show_cards = {}
		for _, v in pairs(cards) do
			if v.card > 0 and not table.has(user_cards, v.card) then
				--没有的牌不能亮
				g.log:deskInfo(uid, "reqShowCard err", msg, user_cards)
				return
			end
			table_insert(show_cards, v.card)
		end
		user:setShowCards(show_cards)
	end
	if not user:getIsShowed() then
		g.desk:setUserShowCard(sid, cards)
	end
	return {code = g.error_code.ok, tid = g.desk_id}
end

--托管
function M:reqAutoOper(msg)
	local uid = msg.mid
	local state = msg.state
	local user = g.user_mgr:getUser(uid)
	if not user then
		return {code = g.error_code.desk_user_err, tid = g.desk_id}
	end
	g.log:deskInfo(uid, "reqAutoOper:", msg)
	if state and state == 0 then
		user:checkComeback()
	end
	return {code = g.error_code.ok, tid = g.desk_id}
end






-----------------------------------------------------------------

--掉线了
function M:onDisconnect(msg)
	local uid = msg.uid
	local agent = msg.agent
	g.log:deskInfo(uid, "onDisconnect", msg)
	local user = g.user_mgr:getUser(uid)
	if not user then --玩家不在这个桌子里
		g.log:deskInfo(uid, "onDisconnect not in desk", msg)
		return
	end
	if user:getAgent() ~= agent then
		--断开后，重新登录后agent是会改变
		g.log:deskInfo(uid, "onDisconnect agent change", agent, user:getAgent())
		return
	end
	user:setDisconnect(true)
	local res
	if g.desk.disconnectCallback then
		res = g.desk:disconnectCallback(user)
	end
	return true
end

--正在玩的人数
function M:onGetPlayingNum()
	local num = g.user_mgr:getPlayingUserNum()
	return num
end

--坐着的人数
function M:onGetSeatingNum()
	local num = g.user_mgr:getSeatUsersNum()
	return num
end

--总的人数
function M:onGetUsersNum()
	local num = g.user_mgr:getUsersNum()
	return num
end


--删除玩家
function M:onKickUser(uid)
	local user = g.user_mgr:getUser(uid)
	if not user then --玩家不在这个桌子里
		g.log:deskInfo(uid, "onKickUser not in desk")
		return
	end
	if g.desk:isMatchRoom() then
		--比赛场的不用踢
		g.log:deskInfo(uid, "onKickUser isMatchRoom cant use")
		return
	end
	g.desk:kickUser(user)
	return {code = g.error_code.ok, tid=g.tid}
end

--删除所有机器人
function M:onRemoveRobots()
	self.remove_robots = true
	g.desk:removeRobots()
	return {code = g.error_code.ok, tid=g.tid}
end

function M:testHotfix()
	--print("testHotfix111111111122222")
	--if not g.user_mgr then return end
	--local user = g.user_mgr:getUser(100)
	--if  not user then return end
	--user:setNoOperNum(1)
	--self:reqAutoOper({
	--	mid = 100,
	--	state = 0,
	--})
end
------------------------------------------------------------------------------------------------



return M